import Vue from 'vue'
import Vuex, {Store} from 'vuex'
import Router from 'vue-router'
import pathToRegexp from 'path-to-regexp'

import mixins from './mixins'
import component, {structureTabbar} from './component'
import plugin from './plugin'
import utils from './utils'
import cache from './cache'

import 'lib-flexible'

class badEgg {
  constructor (options){

    this.router = options.router || []
    this.routerMixins = options.routerMixins || []
    this.store = options.store || {}
    this.pageSwithAnimation = options.pageSwithAnimation || 'default'
    this.tabbarConfig = options.tabbar
    this.splash = {
      status: options.splash === undefined ? false : true,
      components: options.splash || null
    }

    this.before = options.before || null

    this.beforeEach = options.beforeEach || null
    this.beforeResolve = options.beforeResolve || null
    this.afterEach = options.afterEach || null
    window.apps = this
  }

  init(el) {
    this.res = {}
    const template = this.res.template = this.createTemplate()
    const data = this.res.data = this.createData()
    const computed = this.res.computed = this.createComputed()
    const store = this.res.store = this.createStore()
    const router = this.res.router = this.createRouter()
    const methods = this.res.methods = this.createMethods()
    const watch = this.res.watch = this.createWatch()
    const beforeCreate = this.res.beforeCreate = this.createBeforeCreate()
    const created = this.res.created = this.createCreated()
    const beforeMount = this.res.beforeMount = this.createMount()

    //处理tabbar组件
    this.tabbar()

    //注册全局组件
    component.call(this)

    //注册插件
    plugin.call(this)

    Vue.config.productionTip = false
    return window.app = this.app = new Vue({
      el,
      router,
      store,
      template,
      data,
      computed,
      methods,
      watch,
      beforeCreate,
      created,
      beforeMount,
    })
  }

  //创建路由组件mixins
  bindRouterMixins(routes, key) {
    routes.map(route => {
      const components = route.component
      mixins({components, key})
      if(route.children instanceof Array && route.children.length)
        this.bindRouterMixins(route.children, key)
    })
  }

  //创建路由
  createRouter() {

    Vue.use(Router)
    const routes = this.router
    const routerMixins = this.routerMixins
    const defaultRouterMixins = [
      "SetAnimation",
      "CacheRouter",
    ]
    const _mixins = utils.mergeArray(routerMixins, defaultRouterMixins)

    _mixins.map(key => {
      this.bindRouterMixins(routes, key)
    })

    const router = new Router({
      routes
    })

    //注册路由全局钩子
    router.beforeEach((to, from, next) => {
      if(from.name === null && to.query.VNK){
        Vue.navigation.cleanRoutes()
      }

      if(!to.query.VNK)
        return next()

      if(!this.beforeEach)
        return next()

      this.beforeEach(to, from, next)
    })

    router.beforeResolve((to, from, next) => {
      if(!this.beforeResolve)
        return next()

      this.beforeResolve(to, from, next)
    })

    router.afterEach((to, from) => {
      if(this.afterEach)
        return this.afterEach(to, from)
    })

    //重置router方法，增加动画
    router.push = function(location, onComplete, onAbort) {
      this.app.options.setAnimation = this.app.options.setAnimation || 'forward'
      this.history.push(location, onComplete, onAbort);
    }
    router.replace = function(location, onComplete, onAbort) {
      this.app.options.setAnimation = this.app.options.setAnimation || 'forward'
      this.history.replace(location, onComplete, onAbort);
    }
    router.go = function(n) {
      if(n > 0)
        this.app.options.setAnimation = this.app.options.setAnimation || 'forward'
      else if(n < 0)
        this.app.options.setAnimation = this.app.options.setAnimation || 'back'

      this.history.go(n);
    }

    return router
  }

  //创建store
  createStore() {
    Vue.use(Vuex)
    const splash = this.createSplash()
    const before = this.createBefore()
    this.store.modules = this.store.modules || {}
    this.store.modules.options = {
      state: {
        pageSwithAnimation: this.pageSwithAnimation,
        setAnimation: '',
        splash,
        before,
        beforeStatus: splash || before ? false : true,
      },
      mutations: {
        changePageSwithAnimation(state, animation){
          state.pageSwithAnimation = animation
        }
      }
    }
    this.store.state = this.store.state || {}
    this.store.mutations = this.store.mutations || {}

    Object.assign(this.store.state, {
      cache: [],
    })

    Object.assign(this.store.mutations, {
      addCache(state, key){
        if(state.cache.indexOf(key) === -1)
          state.cache.push(key)
      },
      deleteCache(state, key){
        const cache = state.cache
        const start = cache.indexOf(key)
        const end = cache.length - 2
        for(let i = start; i <= end; i++){
          cache.pop()
        }
      }
    })

    return new Store(this.store)
  }

  //创建Vue组件模板
  createTemplate() {
    const splashStatus = this.splash.status
    return `
      <transition
        :name="options.pageSwithAnimation"
        v-on:after-leave="afterLeave"
      >
        <router-view v-if="options.beforeStatus" :key="$route.query.VNK" />
        <Splash v-else-if="options.splash || (options.before && ${splashStatus})" />
      </transition>
    `
  }

  //程序执行前的钩子状态
  createBefore() {
    let status = false
    if(this.before)
      status = true
    return status
  }


  createSplash() {
    const splash = this.splash
    const components = splash.components

    const key = 'Splash'
    if(splash.status){
      mixins({components, key})
      Vue.component(key, components)
    }
    return splash.status
  }

  createData() {
    return {
    }
  }

  createComputed() {
    return {
      options() {
        return this.$store.state.options
      },
    }
  }

  createMethods() {
    var self = this
    return {
      afterLeave() {
        if(!self.splash.status)
          return

        self.splash.status = false

        this.options.pageSwithAnimation = this.pageSwithAnimation
      },
      getCache() {
        return Object.assign({}, {}, cache)
      },
    }
  }

  createWatch() {
    return {
      'options.splash'() {
        if(!this.options.splash && !this.options.before)
          this.options.beforeStatus = true
        else
          this.options.beforeStatus = false
      },
      'options.before'() {
        if(!this.options.splash && !this.options.before)
          this.options.beforeStatus = true
        else
          this.options.beforeStatus = false
      }
    }
  }

  createBeforeCreate() {
    return function() {
    }
  }

  createCreated() {

    return function() {
      this.$navigation.on('forward', (to, from) => {

        this.options.pageSwithAnimation = this.options.setAnimation || 'forward'
        this.options.setAnimation = ''

        //缓存数据
        if(from.route.meta.cache && from.route.meta.cache.force === false)
          return

        const vm = this.$children[0]
        const key = from.name
        const forceCache = cache[key] && cache[key].$forceCache || undefined
        const dataTemplate = from.route.matched[0] ? from.route.matched[0].components.default.data() : false

        if(!dataTemplate)
          return

        this.$store.commit('addCache', key)

        let data = {}
        for(var i in dataTemplate)
          data[i] = vm[i]

        data = JSON.parse(JSON.stringify(data))

        data.$forceCache = forceCache
        cache[key] = data
      })

      this.$navigation.on('back', (to, from) => {
        this.options.pageSwithAnimation = this.options.setAnimation || 'back'
        this.options.setAnimation = ''

        //监听路由back事件，删除过期缓存数据
        if(from.route.meta.cache && from.route.meta.cache.force === false)
          return

        const key = to.name
        const data = cache[key]
        const record = this.$store.state.cache
        const index = record.indexOf(key)
        const length = record.length
        let force = false

        for(let i = index + 1; i < length; i++){
          if(!force && (data.$forceCache && cache[record[i]].$forceCache === true ? false : true))
            force = true

          if(force)
            delete cache[record[i]]
        }

        this.$store.commit('deleteCache', key)

      })

      this.$navigation.on('replace', (to, from) => {
        this.options.pageSwithAnimation = this.options.setAnimation || 'forward'
        this.options.setAnimation = ''

        //强制缓存replace数据
        if(!from.route.meta.cache || from.route.meta.cache.force !== true)
          return

        const vm = this.$children[0]
        const key = from.name
        const dataTemplate = from.route.matched[0].components.default.data()

        this.$store.commit('addCache', key)

        let data = {}
        for(var i in dataTemplate)
          data[i] = vm[i]

        data = JSON.parse(JSON.stringify(data))
        data.$forceCache = true
        cache[key] = data

      })

    }
  }

  createMount() {
    const beforeCallback = this.before
    const pageSwithAnimation = this.pageSwithAnimation
    if(this.before)
      return function() {
        beforeCallback(animation => {
          if(animation)
            this.options.pageSwithAnimation = animation
          this.options.before = false
          setTimeout(() => {
            this.options.pageSwithAnimation = pageSwithAnimation
          },0)
        })
      }
    return null
  }

  tabbar() {
    const tabbarOptions = this.tabbarConfig
    if(tabbarOptions){
      structureTabbar.components = {}
      const DOM = utils.createElement('section', 'body', {
        'display': 'none'
      })
      for(let i in tabbarOptions){
        const config = tabbarOptions[i]
        const id = i
        const item = config.items
        const component = {
          methods: {
            nav(e) {
              const index = parseInt(e.el.getAttribute('index'))
              if(item[index].path){
                this.$parent.$parent.$parent.setAnimation('tabbar_replace')
                this.$router.replace(item[index].path)
              }
            },
            getIndex(path, id){
              if(path === this.path){
                this.index = 1
                return true
              }else return false
            },
            regexpPath(regexp) {
              return pathToRegexp(regexp).exec(this.path) ? true : false
            }
          },
          computed: {
            path() {
              return this.$route.path
            }
          },
          mounted() {
            const fullPath = this.$route.fullPath
            const parent = this.$parent.$el
            const index = parseInt(parent.querySelector(`#${id} > .select`).getAttribute('index'))

            if(item[index].path)
              item[index].path = fullPath
          }
        }
        const navComponent = {}
        let template = config.template
        DOM.innerHTML = template

        let html = ''
        for(let c = 0; c < item.length; c++){
          let id = `navchildren_${c}`
          const items = item[c]
          navComponent[id] = item[c].components
          html += `
            <${id}
             v-tap="nav"
             :class="{
               select: regexpPath('${items.path}')
             }"
             index="${c}"
            ></${id}>
          `
        }
        template = DOM.querySelector(`#${id}`)
        if(!template)
          return
        template.innerHTML = html
        template = DOM.innerHTML
        component.template = template
        component.components = navComponent
        structureTabbar.components[id] = component
      }
      DOM.remove()
    }
  }

}

badEgg.utils = utils

export default badEgg
export {
  utils
}
